home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Interactive Reference Guide
/
C-C++ Interactive Reference Guide.iso
/
c_ref
/
csource3
/
186_01
/
view151.c
< prev
next >
Wrap
Text File
|
1985-08-21
|
15KB
|
484 lines
/* VIEW: Displays text files. CR advances by line, SPACE by screen.
* BS goes backwards by line, ESC by screen. ^B returns to beginning,
* ^E goes to end. ^C to abort.
* Syntax: VIEW [-t] [n/][d:]filename.typ {more filenames . . .}
* "t" = tab size (defaults to 8 spaces)
* Multiple filenames on command line allowed. Ambiguous filenames allowed
* (see WILDEXP.C documentation).
*
* Version 1.5 -- 10/10/85
* Version 1.51 (with slight changes for portability) -- 12/09/85
*
* James Pritchett
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Compiling instructions:
*
* VIEW was originally written to use memory-mapping for all video output
* via an enhanced version of the BDS "txtplot" function. The source for
* txtplot() (version for the NEC PC-8801A computer) is given in the file
* TXTPLOT.CSM, and can easily be adapted for other systems supporting
* memory-mapped video. The file TXTPLOT.C contains a version of the same
* function, written in C, that does NOT use memory-mapping. See the
* file VIEW151.DOC for more info on these functions.
*
* The commands to compile/link VIEW:
*
* WITH memory-mapping:
* SUBMIT CASM TXTPLOT
* CC VIEW
* L2 VIEW TXTPLOT -L WILDEXP
*
* WITHOUT memory-mapping:
* CC TXTPLOT
* CC VIEW
* L2 VIEW TXTPLOT -L WILDEXP
*
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <bdscio.h>
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * *
* NON-USER DEFINED SYMBOLS *
* * * * * * * * * * * * * * */
/* None of these symbols should need revision for porting to other systems */
/* For opening message */
#define VERSION "1.51"
#define DATE "10/10/85 (12/09/85)"
/* File buffer definitions */
/* NOTE: If your TPA is too small to handle a 32K buffer, or
* if your TPA is really big and can handle more, then you
* should reset SEGBLKS to an appropriate number.
*/
#define SEGBLKS 128 /* 128 recs per segment */
#define SEGSIZE (SEGBLKS * SECSIZ) /* segment = 16K */
#define FBLKS (2 * SEGBLKS) /* 2 segments at a time */
#define FSIZE (2 * SEGSIZE) /* 2 segments in buffer */
#define xseg buffer /* xseg at top of buffer */
/* Macros for buffer-handling */
#define atend() (*botptr == CPMEOF)
#define attop() ((topptr == xseg) && !curxseg)
#define topfault(p) ((p < (xseg+2)) && curxseg)
#define botfault(p) ((p == bufend) && !lastseg)
/* ASCII defines */
#define CNTLB 0x02
#define CNTLC 0x03
#define CNTLE 0x05
#define BS 0x08
#define LF 0x0a
#define CR 0x0d
#define CNTLN 0x0e
#define ESC 0x1b
#define MASK 0x7f /* for parity-strip */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * *
* USER-DEFINED SYMBOLS *
* * * * * * * * * * * * */
/* The following should be customized for individual systems. The
* values given here are for an NEC PC-8801A computer.
*/
/* Screen size: */
#define MAXROW 24 /* Number of rows on screen */
#define LASTROW 23 /* MAXROW-1 */
/* Memory-mapped video parameters: */
#define BASE 0x0f300 /* Video memory base address */
#define XSIZE 24 /* Number of lines in display */
#define YSIZE 120 /* Characters per line */
/* Macros for screen routines:
*
* The following four functions are defined as macros: clear screen,
* home cursor, move cursor to bottom right corner of screen, insert
* blank line at cursor location. These will probably have to be
* customized for the proper escape/control sequences for a particular
* terminal/computer. If any of these are not available as simple
* escape/control sequences, you may want to write functions to perform
* the same actions. Also, if you use the non-memory-mapped version of
* TXTPLOT, you may want to define "cursbot" as a call to the "gotoxy"
* function given in TXTPLOT.C. Otherwise, this is the only "gotoxy"
* call in the program, so a separate function is unnecessary.
*/
#define clear() putch(CNTLZ)
#define home() putch(0x01e)
#define cursbot() putch(ESC); putch('='); putch('7'); putch('m')
#define lnins() putch(ESC); putch('E')
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* global variables */
int tabsiz; /* Size of tabs (= 8 or given on command line) */
int curxseg; /* Number of first segment in memory */
int lastseg; /* = TRUE if last segment of file is in
* memory, FALSE if not.
*/
int fd;
int lastrow; /* Last row plotted on screen */
char *topptr, *botptr; /* Pointers into text buffer. These point
* to the lines of text at top and bottom of
* screen.
*/
char *yseg; /* Pointer to second buffer segment */
char *bufend; /* Pointer to end of buffer */
char buffer[FSIZE];
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
main(argc,argv)
int argc;
char **argv;
{
char c;
wildexp(&argc, &argv);
printf("VIEW -- Version %s James Pritchett, %s\n\n",VERSION,DATE);
/* If too few arguments, give a usage summary */
if (argc < 2) {
printf("USAGE: VIEW [-t] <list of files>\n");
printf(" t = tab size (defaults to 8 spaces)\n");
printf(" Ambiguous filenames allowed\n");
exit();
}
/* Tabsize argument must be first argument */
if (*(argv[1]) == '-') {
tabsiz = atoi(argv[1]+1);
if (!tabsiz) /* If error on atoi, set to default */
tabsiz = 8;
argc--;
argv++; /* Point past the tab argument */
}
else
tabsiz = 8;
printf("\t<RET> = Forward line <SPACE> = Forward screen\n");
printf("\t<BS> = Backward line <ESC> = Backward screen\n");
printf("\t^B = Top of file ^E = End of file\n");
printf("\t^N = Next file ^C = Exit program\n");
/* Initialize memory-mapped video */
setplot(BASE,XSIZE,YSIZE);
/* Set up buffer pointers */
bufend = buffer + FSIZE - 1;
yseg = buffer + SEGSIZE;
/* Main event: Get files and process commands */
while (--argc) {
if (getfile(*(++argv)) == ERROR)
continue; /* just skip bad filenames */
while ((c = getchar()) != CNTLN) {
switch (c) {
case CR: nextln();
break;
case ' ': nextscn();
break;
case BS: backln();
break;
case ESC: backscn();
break;
case CNTLB: tobegin();
break;
case CNTLE: toend();
break;
case CNTLC: exit();
}
cursbot(); /* Re-locate cursor after all commands */
}
close(fd);
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int getfile(fname) /* Read in a file */
char *fname;
{
topptr = 0; /* reset this pointer when opening new file */
if ((fd = open(fname,0)) == ERROR) {
printf("\nERROR: Can't open file.\n");
return(ERROR);
}
printf("\nLoading %s . . .",fname);
curxseg = 1; /* this causes tobegin() to load the file */
tobegin(); /* Load and display first screen */
cursbot(); /* Locate cursor out of the way */
return(0); /* Return OK */
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void fillbuff(seg) /* Fill the buffer with two file segments, starting
* with "seg".
*/
int seg;
{
int numread;
lastseg = FALSE; /* Start from this assumption */
curxseg = seg; /* First segment = seg */
seek(fd,(seg * SEGBLKS),0); /* find it */
if ((numread = read(fd,buffer,FBLKS)) == ERROR) {
printf("\nERROR: Disk read error.\n");
exit(); /* all read errors crash the program */
}
/* If we didn't fill the buffer, or if the last char is an EOF, then
* this must be all there is, and the last segment of the file is
* in memory. So set the flag TRUE.
*/
if ((numread != FBLKS) || (*bufend == CPMEOF))
lastseg = TRUE;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void nextln() /* Go forward one line */
{
char *temp;
if (atend())
return;
putch(LF); /* this causes a scroll up one line */
temp = ptrdown(botptr); /* be sure segfault is taken care of first */
topptr = ptrdown(topptr);
txtplot(botptr,LASTROW,0,tabsiz); /* if there was a segfault, */
botptr = temp; /* botptr was revised */
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void nextscn() /* Go forward one screen */
{
if (atend())
return;
topptr = botptr; /* botptr => next topline */
dispscn();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void backln() /* Go back one line */
{
if (attop())
return;
home();
lnins(); /* a scroll down */
topptr = ptrup(topptr);
if (lastrow < MAXROW) /* bug fix: if last screen has < 24 lines, botptr */
lastrow++; /* should remain unchanged */
else
botptr = ptrup(botptr);
txtplot(topptr,0,0,tabsiz);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void backscn() /* Go backward one screen */
{
int x;
if (attop())
return;
for (x = 0; x < MAXROW && !attop(); x++)
topptr = ptrup(topptr); /* move back 24 lines or to beginning */
dispscn();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void tobegin() /* Go to beginning of file */
{
if (attop())
return;
if (curxseg) /* seek to beginning if segment 0 is not in memory */
fillbuff(0);
topptr = buffer;
dispscn();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void toend() /* Go to end of file */
{
int x, lastxseg;
if (atend())
return;
if (!lastseg) { /* seek to end if not in memory */
lastxseg = ((cfsize(fd) - 1)/SEGBLKS) - 1;
fillbuff(lastxseg);
botptr = yseg;
}
while (!atend()) /* find the bottom of file first */
botptr = ptrdown(botptr);
topptr = botptr;
for (x = 0; x < MAXROW && !attop(); x++)
topptr = ptrup(topptr); /* then figure topline from there */
dispscn();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *ptrdown(ptr) /* Move a pointer down one line in buffer */
char *ptr;
{
while (*ptr != CPMEOF) {
if (botfault(ptr)) { /* if we have more to read, then do so */
ptr = bufup(ptr);
readseg(yseg);
}
if (((*ptr++) & MASK) == LF) /* strip parity */
break;
}
return ptr;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *ptrup(ptr) /* Move a pointer up one line in buffer */
char *ptr;
{
if (topfault(ptr)) { /* we have to check before skipping back */
ptr = bufdn(ptr); /* over LF */
readseg(xseg);
}
ptr--; /* go back past LF */
while ((*(ptr - 1) & MASK) != LF && (ptr != buffer)) {
if (topfault(ptr)) { /* and check while going back */
ptr = bufdn(ptr);
readseg(xseg);
}
ptr--;
}
return ptr;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dispscn() /* Fill the screen, starting from *topptr */
{
char *temp;
/* note: this routine displays MAXROW lines, or as many as remain in
* file, whichever is less, starting with the line pointed to by
* topptr. It locates the next line, THEN displays the current
* line, so as to force any segment faults before displaying the
* line in which that fault occurred. temp points to the next line,
* botptr to the current line. If a segfault occurs, botptr will
* be adjusted as necessary by bufup(), thus assuring the proper
* current line will be displayed. At the conclusion of this
* routine, botptr is pointing to the next line in the file, or
* to the end of file, and lastrow = the number of lines currently
* on the screen (botptr should not be moved up until MAXROW lines are
* on the screen).
*/
clear();
for (lastrow = 0, botptr = topptr; lastrow < MAXROW && !atend();
lastrow++, botptr = temp) {
temp = ptrdown(botptr);
txtplot(botptr,lastrow,0,tabsiz);
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char getchar() /* gets a char with no echo */
{
char c;
while (!(c = bdos(6,-1)))
;
return c;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *bufup(p) /* Move yseg into xseg position */
char *p;
{
movmem(yseg,xseg,SEGSIZE);
p -= SEGSIZE; /* revise all pointers */
topptr -= SEGSIZE;
botptr -= SEGSIZE;
return(p);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char *bufdn(p) /* Move xseg into yseg position */
char *p;
{
movmem(xseg,yseg,SEGSIZE);
p += SEGSIZE; /* revise all pointers */
topptr += SEGSIZE;
botptr += SEGSIZE;
return(p);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void readseg(segstart) /* routine to read in a new segment */
char *segstart; /* segstart is where the segment is to go */
{
int firstrec, numread;
if (segstart == xseg) { /* if we're reading in a new xseg, */
curxseg--; /* then we're scrolling backwards */
firstrec = curxseg * SEGBLKS;
}
else { /* if we're reading a yseg, then we're scrolling forwards */
curxseg++;
firstrec = (curxseg + 1) * SEGBLKS;
}
seek(fd,firstrec,0);
if ((numread = read(fd,segstart,SEGBLKS)) == ERROR) {
printf("\nERROR: Disk read error.\n");
exit(); /* all read errors crash the program */
}
if ((numread != SEGBLKS) || (*bufend == CPMEOF))
lastseg = TRUE;
}
/* end */
movmem(xseg,yseg,SEGSIZE);
p +=